//
//  NSString+Safe.m
//  niuguwang
//
//  Created by BrightLi on 2021/5/15.
//  Copyright © 2021年 taojinzhe. All rights reserved.
//

#import "NSString+Safe.h"
#import "YMSafeUtil.h"

@implementation NSString(Safe)

+ (void) safe_fixed
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class cls = NSClassFromString(@"__NSCFConstantString");
        //characterAtIndex
        [YMSafeUtil swizzleInstance:cls
                          sel1:@selector(characterAtIndex:)
                          sel2:@selector(safe_characterAtIndex:)];
        //substringFromIndex
        [YMSafeUtil swizzleInstance:cls
                          sel1:@selector(substringFromIndex:)
                          sel2:@selector(safe_substringFromIndex:)];
        //substringToIndex
        [YMSafeUtil swizzleInstance:cls
                          sel1:@selector(substringToIndex:)
                          sel2:@selector(safe_substringToIndex:)];
        //substringWithRange:
        [YMSafeUtil swizzleInstance:cls
                          sel1:@selector(substringWithRange:)
                          sel2:@selector(safe_substringWithRange:)];
        //stringByReplacingOccurrencesOfString:
        [YMSafeUtil swizzleInstance:cls
                          sel1:@selector(stringByReplacingOccurrencesOfString:withString:)
                          sel2:@selector(safe_stringByReplacingOccurrencesOfString:withString:)];
        //stringByReplacingOccurrencesOfString:withString:options:range:
        [YMSafeUtil swizzleInstance:cls
                          sel1:@selector(stringByReplacingOccurrencesOfString:withString:options:range:)
                          sel2:@selector(safe_stringByReplacingOccurrencesOfString:withString:options:range:)];
        //stringByReplacingCharactersInRange:withString:
        [YMSafeUtil swizzleInstance:cls
                          sel1:@selector(stringByReplacingCharactersInRange:withString:)
                          sel2:@selector(safe_stringByReplacingCharactersInRange:withString:)];
    });
}

- (unichar) safe_characterAtIndex:(NSUInteger)index
{
    unsigned short result=0;
    if(index<self.length){
        result=[self safe_characterAtIndex:index];
    }else{
        [YMSafeUtil log:@"[NSString characterAtIndex:%lu]出界 [%@]",(unsigned long)index,self];
    }
    return result;
}

- (NSString *) safe_substringFromIndex:(NSUInteger)from
{
    NSString *subString = @"";
    if(from<self.length){
        subString = [self safe_substringFromIndex:from];
    }else{
        [YMSafeUtil log:@"[NSString substringFromIndex:%lu]出界 [%@]",(unsigned long)from,self];
    }
    return subString;
}

- (NSString *) safe_substringToIndex:(NSUInteger)from
{
    NSString *subString = @"";
    if(from<self.length){
        subString = [self safe_substringToIndex:from];
    }else{
        [YMSafeUtil log:@"[NSString substringToIndex:%lu]出界 [%@]",(unsigned long)from,self];
    }
    return subString;
}

- (NSString *)safe_substringWithRange:(NSRange)range
{
    NSString *subString = @"";
    if((range.location+range.length)<=self.length){
        subString = [self safe_substringWithRange:range];
    }else{
        [YMSafeUtil log:@"[NSString substringWithRange:%lu-%lu]出界[%@]",(unsigned long)range.location,(unsigned long)range.length,self];
    }
    return subString;
}

- (NSString *) safe_stringByReplacingOccurrencesOfString:(NSString *)target
                                          withString:(NSString *)replacement
                                             options:(NSStringCompareOptions)options
                                               range:(NSRange)searchRange {
    NSString *newStr = @"";
    @try {
        newStr = [self safe_stringByReplacingOccurrencesOfString:target withString:replacement options:options range:searchRange];
    }
    @catch (NSException *exception) {
        [YMSafeUtil stackLog:exception start:4];
    }
    @finally {
        return newStr;
    }
}

- (NSString *)safe_stringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement
{
    NSString *newStr = nil;
    @try {
        newStr = [self safe_stringByReplacingOccurrencesOfString:target withString:replacement];
    }
    @catch (NSException *exception) {
        [YMSafeUtil stackLog:exception start:5];
    }
    @finally {
        return newStr;
    }
}

- (NSString *) safe_stringByReplacingCharactersInRange:(NSRange)range withString:(NSString *)replacement
{
    NSString *newStr = nil;
    @try {
        newStr=[self safe_stringByReplacingCharactersInRange:range withString:replacement];
    }
    @catch (NSException *exception) {
        [YMSafeUtil stackLog:exception start:5];
    }
    @finally {
        return newStr;
    }
}

@end

@implementation NSMutableString (Safe)

+ (void) safe_fixed
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class cls = NSClassFromString(@"__NSCFString");
        [YMSafeUtil swizzleInstance:cls
                          sel1:@selector(replaceCharactersInRange:withString:)
                          sel2:@selector(safe_replaceCharactersInRange:withString:)];
        [YMSafeUtil swizzleInstance:cls
                          sel1:@selector(replaceOccurrencesOfString:withString:options:range:)
                          sel2:@selector(safe_replaceOccurrencesOfString:withString:options:range:)];
        [YMSafeUtil swizzleInstance:cls
                          sel1:@selector(insertString:atIndex:)
                          sel2:@selector(safe_insertString:atIndex:)];
        [YMSafeUtil swizzleInstance:cls
                          sel1:@selector(deleteCharactersInRange:)
                          sel2:@selector(safe_deleteCharactersInRange:)];
        [YMSafeUtil swizzleInstance:cls
                          sel1:@selector(appendString:)
                          sel2:@selector(safe_appendString:)];
    });
}

- (void)safe_replaceCharactersInRange:(NSRange)range
                        withString:(NSString *)aString
{
    @try {
        [self safe_replaceCharactersInRange:range withString:aString];
    }
    @catch (NSException *exception) {
        [YMSafeUtil stackLog:exception start:5];
    }
    @finally {
    }
}

- (NSUInteger)safe_replaceOccurrencesOfString:(NSString *)target withString:(NSString *)replacement options:(NSStringCompareOptions)options range:(NSRange)searchRange
{
    NSUInteger index = 0;
    @try {
        index = [self safe_replaceOccurrencesOfString:target withString:replacement options:options range:searchRange];
    }
    @catch (NSException *exception) {
        [YMSafeUtil stackLog:exception start:5];
    }
    @finally {
        return index;
    }
}

- (void) safe_insertString:(NSString *)aString
               atIndex:(NSUInteger)loc
{
    @try {
        [self safe_insertString:aString atIndex:loc];
    }
    @catch (NSException *exception) {
        [YMSafeUtil stackLog:exception start:5];
    }
    @finally {
    }
}

- (void) safe_deleteCharactersInRange:(NSRange)range
{
    @try {
        [self safe_deleteCharactersInRange:range];
    }
    @catch (NSException *exception) {
        [YMSafeUtil stackLog:exception start:5];
    }
    @finally {
    }
}

- (void)safe_appendString:(NSString *)string {
    @try {
        [self safe_appendString:string];
    }
    @catch (NSException *exception) {
        [YMSafeUtil stackLog:exception start:5];
    }
    @finally {
    }
}

@end

@implementation NSAttributedString (Safe)

+ (void) safe_fixed {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class cls = NSClassFromString(@"NSConcreteAttributedString");
        [YMSafeUtil swizzleInstance:cls
                          sel1:@selector(initWithString:)
                          sel2:@selector(safe_initWithString:)];
        [YMSafeUtil swizzleInstance:cls
                          sel1:@selector(initWithAttributedString:)
                          sel2:@selector(safe_initWithAttributedString:)];
        [YMSafeUtil swizzleInstance:cls
                          sel1:@selector(initWithString:attributes:)
                          sel2:@selector(safe_initWithString:attributes:)];
        [YMSafeUtil swizzleInstance:cls
                          sel1:@selector(attributedSubstringFromRange:)
                          sel2:@selector(safe_attributedSubstringFromRange:)];
    });
}


- (instancetype) safe_initWithString:(NSString *)str
{
    id object = nil;
    if(str){
        object = [self safe_initWithString:str];
    }else{
        [YMSafeUtil log:@"[NSConcreteAttributedString initWithString:]参数不能为空值"];
    }
    return object;
}

- (instancetype)safe_initWithAttributedString:(NSAttributedString *)attrStr {
    id object = nil;
    @try {
        object = [self safe_initWithAttributedString:attrStr];
    }
    @catch (NSException *exception) {
        [YMSafeUtil stackLog:exception start:5];
    }
    @finally {
        return object;
    }
}

- (instancetype)safe_initWithString:(NSString *)str
                      attributes:(NSDictionary<NSString *, id> *)attrs
{
    id object = nil;
    if(!str){
        str=@"";
        [YMSafeUtil log:@"[NSConcreteAttributedString initWithString:attributes:]str参数不能为空值"];
    }else if(!attrs){
        attrs=@{};
        [YMSafeUtil log:@"[NSConcreteAttributedString initWithString:attributes:]attrs参数不能为空值"];
    }
    object = [self safe_initWithString:str attributes:attrs];
    return object;
}

- (NSAttributedString *)safe_attributedSubstringFromRange:(NSRange)range
{
    if (range.location + range.length <= self.length){
        return [self safe_attributedSubstringFromRange:range];
    } else if (range.location < self.length) {
        NSRange fixedRange=NSMakeRange(range.location, self.length-range.location);
        NSAttributedString *result=[self safe_attributedSubstringFromRange:fixedRange];
        return result;
    }
    return self;
}

@end

@implementation NSMutableAttributedString (Safe)

+ (void) safe_fixed
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class cls = NSClassFromString(@"NSConcreteMutableAttributedString");
        [YMSafeUtil swizzleInstance:cls
                          sel1:@selector(initWithString:)
                          sel2:@selector(safe_initWithString:)];
        [YMSafeUtil swizzleInstance:cls
                          sel1:@selector(initWithString:attributes:)
                          sel2:@selector(safe_initWithString:attributes:)];
        [YMSafeUtil swizzleInstance:cls
                          sel1:@selector(attributedSubstringFromRange:)
                          sel2:@selector(safe_attributedSubstringFromRange:)];
    });
}

- (instancetype)safe_initWithString:(NSString *)str {
    id object = nil;
    @try {
        object = [self safe_initWithString:str];
    }
    @catch (NSException *exception) {
        [YMSafeUtil stackLog:exception start:5];
    }
    @finally {
        return object;
    }
}

- (instancetype) safe_initWithString:(NSString *)str
                       attributes:(NSDictionary<NSString *, id> *)attrs
{
    if(!str){
        str=@"";
    }
    if(!attrs){
        attrs=@{};
    }
    id object = [self safe_initWithString:str attributes:attrs];
    return object;
}

- (NSAttributedString *) safe_attributedSubstringFromRange:(NSRange)range {
    if (range.location + range.length <= self.length) {
        return [self safe_attributedSubstringFromRange:range];
    } else if (range.location < self.length) {
        return [self safe_attributedSubstringFromRange:NSMakeRange(range.location, self.length - range.location)];
    }
    return nil;
}

@end
